#include "Buffer.h"

#include <errno.h>
#include <sys/uio.h>  // readv
#include <unistd.h>

/**
 * 从fd上读取数据  Poller工作在LT模式
 * Buffer缓冲区是有大小的！ 但是从fd上读数据的时候，却不知道tcp数据最终的大小
 */ 
ssize_t Buffer::readFd(int fd, int* saveErrno)
{
    char extrabuf[65536] = {0}; // 创建一个大小为 64KB 的栈上的临时缓冲区
    
    struct iovec vec[2]; // 创建一个 iovec 结构体数组, 用于 readv 函数的参数
    
    const size_t writable = writableBytes(); // 获取当前 Buffer 缓冲区可写的字节数
    vec[0].iov_base = begin() + writerIndex_; // 第一个缓冲区指向 Buffer 中可写部分的起始地址
    vec[0].iov_len = writable; // 第一个缓冲区的长度为可写字节数

    vec[1].iov_base = extrabuf; // 第二个缓冲区指向临时缓冲区的起始地址
    vec[1].iov_len = sizeof extrabuf; // 第二个缓冲区的长度为临时缓冲区的大小
    
    const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; // 确定向内核传递的缓冲区数量
    const ssize_t n = ::readv(fd, vec, iovcnt); // 通过 readv 函数从文件描述符 fd 上读取数据到缓冲区 vec 中
    if (n < 0) // 如果读取失败
    {
        *saveErrno = errno; // 保存错误码
    }
    else if (n <= writable) // Buffer的可写缓冲区已经够存储读出来的数据了
    {
        writerIndex_ += n; // 更新写索引
    }
    else // 如果读取的数据量超过了 Buffer 的可写空间, extrabuf里面也写入了数据 
    {
        writerIndex_ = buffer_.size(); // 更新写索引为缓冲区的末尾
        append(extrabuf, n - writable);  // writerIndex_开始写 n - writable大小的数据
    }

    return n; // 返回读取的字节数
}

// 向文件描述符 fd 写入数据
ssize_t Buffer::writeFd(int fd, int* saveErrno)
{
    ssize_t n = ::write(fd, peek(), readableBytes()); // 调用系统的 write 函数向文件描述符 fd 写入数据
    if (n < 0) // 如果写入失败
    {
        *saveErrno = errno; // 保存错误码
    }
    return n; // 返回写入的字节数
}
